package com.k8sops.backend.service.impl;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.k8sops.backend.common.ApiResponse;
import com.k8sops.backend.model.entity.DOSRelease;
import com.k8sops.backend.service.DOSKubernetesResourceService;
import com.k8sops.backend.service.DOSReleaseService;
import com.k8sops.backend.service.DOSReleaseYamlService;
import com.k8sops.backend.service.DockerRegistryService;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
import io.kubernetes.client.openapi.models.*;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import io.kubernetes.client.util.Yaml;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
public class DOSKubernetesResourceServiceImpl implements DOSKubernetesResourceService {

    @Value("${kubernetes.config.path:~/.kube/config}")
    private String kubeConfigPath;

    @Resource
    private DOSReleaseService dosReleaseService;
    @Resource
    private DOSReleaseYamlService dosReleaseYamlService;
    @Resource
    private DockerRegistryService dockerRegistryService;

    @Override
    public ApiResponse<?> deployYaml(Map<String, String> request) {
        String yamlContent = request.get("yaml");
        String namespace = request.getOrDefault("namespace", "default");
        Integer projectId = request.get("projectId") != null ? Integer.parseInt(request.get("projectId")) : null;
        Integer moduleId = request.get("moduleId") != null ? Integer.parseInt(request.get("moduleId")) : null;
        Integer clusterId = request.get("clusterId") != null ? Integer.parseInt(request.get("clusterId")) : null;
        Integer namespaceId = request.get("namespaceId") != null ? Integer.parseInt(request.get("namespaceId")) : null;
        Integer envType = request.get("envType") != null ? Integer.parseInt(request.get("envType")) : null;
        String releaseName = request.get("releaseName");
        if(StrUtil.isBlank(releaseName)){
            return ApiResponse.<Object>error("releaseName不能为空");
        }
        if (yamlContent == null || yamlContent.trim().isEmpty()) {
            return ApiResponse.<Object>error("YAML内容不能为空");
        }

        // 检查releaseName是否已存在，如果存在则不允许创建
        if (dosReleaseService.existsByReleaseName(releaseName)) {
            log.warn("部署失败：Release名称 '{}' 已存在", releaseName);
            return ApiResponse.<Object>error("部署失败：Release名称 '" + releaseName + "' 已存在，请使用其他名称");
        }

        log.info("开始部署YAML到命名空间: {}", namespace);
        log.debug("YAML内容: {}", yamlContent);

        try {
            // 初始化Kubernetes客户端
            ApiClient client = initializeKubernetesClient();

            // 设置默认的API客户端
            io.kubernetes.client.openapi.Configuration.setDefaultApiClient(client);
            
            // 提取镜像配置信息
            Map<String, Object> imageConfig = extractImageConfig(yamlContent);
            String imageUrl = null;
            if (imageConfig != null) {
                // 构建完整的镜像URL
                imageUrl = dockerRegistryService.buildImageUrl(imageConfig);
                log.info("从配置中构建的镜像URL: {}", imageUrl);
                
                // 确保镜像拉取Secret存在
                String secretName = "common-docker-secret";
                if (imageConfig.containsKey("imagePullSecrets")) {
                    // 如果YAML中已经指定了imagePullSecrets，则使用第一个
                    @SuppressWarnings("unchecked")
                    List<Map<String, String>> secrets = (List<Map<String, String>>) imageConfig.get("imagePullSecrets");
                    if (secrets != null && !secrets.isEmpty() && secrets.get(0).containsKey("name")) {
                        secretName = secrets.get(0).get("name");
                    }
                }
                
                // 创建或确保镜像拉取Secret存在
                dockerRegistryService.createImagePullSecret(namespace, secretName);
            }

            // 解析YAML内容
            List<Object> objects = parseYamlContent(yamlContent);
            if (objects.isEmpty()) {
                return ApiResponse.<Object>error("没有找到有效的Kubernetes资源");
            }

            // 初始化API客户端
            AppsV1Api appsV1Api = new AppsV1Api();
            CoreV1Api coreV1Api = new CoreV1Api();
            NetworkingV1Api networkingV1Api = new NetworkingV1Api();

            // 部署所有资源
            Map<String, Object> result = deployAllResources(objects, namespace, appsV1Api, coreV1Api, networkingV1Api);
            result.put("namespace", namespace);
            
            // 如果有镜像URL，添加到结果中
            if (imageUrl != null) {
                result.put("imageUrl", imageUrl);
            }

            // 保存部署信息到dos_release表
            saveDeploymentInfo(result, releaseName, projectId, moduleId, clusterId, namespaceId, envType, yamlContent);

            // 返回部署结果
            return createDeploymentResponse(result);
        } catch (Exception e) {
            log.error("处理YAML时出错", e);
            return ApiResponse.<Object>error("处理YAML时出错: " + e.getMessage());
        }
    }

    /**
     * 初始化Kubernetes客户端
     */
    private ApiClient initializeKubernetesClient() throws IOException {
        try {
            // 尝试从系统路径加载
            ApiClient client = ClientBuilder.kubeconfig(
                            KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath)))
                    .build();
            // 禁用主机名验证
            client.setVerifyingSsl(false);
            return client;
        } catch (IOException e) {
            log.warn("无法从路径加载kubeconfig: {}, 使用默认配置", kubeConfigPath, e);
            // 如果无法加载，使用集群内配置
            ApiClient client = ClientBuilder.cluster().build();
            // 禁用主机名验证
            client.setVerifyingSsl(false);
            return client;
        }
    }

    /**
     * 解析YAML内容
     */
    private List<Object> parseYamlContent(String yamlContent) {
        List<Object> objects = new ArrayList<>();
        try {
            // 尝试解析为多资源YAML
            Yaml.loadAll(new StringReader(yamlContent)).forEach(objects::add);
        } catch (Exception e) {
            try {
                // 如果解析多资源失败，尝试解析为单资源
                Object obj = Yaml.load(new StringReader(yamlContent));
                if (obj != null) {
                    objects.add(obj);
                }
            } catch (Exception ex) {
                log.error("解析YAML内容失败", ex);
            }
        }
        return objects;
    }
    
    /**
     * 从原始YAML内容中提取镜像配置
     * 
     * @param yamlContent YAML内容
     * @return 镜像配置信息，如果不存在则返回null
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> extractImageConfig(String yamlContent) {
        try {
            // 使用Jackson的YAML解析
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            Map<String, Object> yamlMap = mapper.readValue(yamlContent, Map.class);
            
            // 尝试获取image配置部分
            if (yamlMap.containsKey("image")) {
                return (Map<String, Object>) yamlMap.get("image");
            }
            
            return null;
        } catch (Exception e) {
            log.error("从原始YAML中提取镜像配置失败", e);
            return null;
        }
    }

    /**
     * 部署所有资源
     */
    private Map<String, Object> deployAllResources(List<Object> objects, String namespace,
                                                   AppsV1Api appsV1Api, CoreV1Api coreV1Api,
                                                   NetworkingV1Api networkingV1Api) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> resources = new ArrayList<>();

        for (Object obj : objects) {
            Map<String, Object> resourceResult = handleKubernetesResource(
                    obj, namespace, appsV1Api, coreV1Api, networkingV1Api);

            if (!resourceResult.isEmpty() && StrUtil.isNotBlank((CharSequence) resourceResult.get("error"))) {
                resources.add(resourceResult);
            }
        }

        result.put("resources", resources);
        return result;
    }

    /**
     * 处理Kubernetes资源
     */
    private Map<String, Object> handleKubernetesResource(Object obj, String namespace,
                                                         AppsV1Api appsV1Api, CoreV1Api coreV1Api,
                                                         NetworkingV1Api networkingV1Api) {
        Map<String, Object> resourceResult = new HashMap<>();

        try {
            if (obj instanceof V1Deployment) {
                resourceResult = deployDeployment((V1Deployment) obj, namespace, appsV1Api);
            } else if (obj instanceof V1Service) {
                resourceResult = deployService((V1Service) obj, namespace, coreV1Api);
            } else if (obj instanceof V1Ingress) {
                resourceResult = deployIngress((V1Ingress) obj, namespace, networkingV1Api);
            } else if (obj instanceof V1ConfigMap) {
                resourceResult = deployConfigMap((V1ConfigMap) obj, namespace, coreV1Api);
            } else if (obj instanceof V1Secret) {
                resourceResult = deploySecret((V1Secret) obj, namespace, coreV1Api);
            } else if (obj instanceof V1StatefulSet) {
                resourceResult = deployStatefulSet((V1StatefulSet) obj, namespace, appsV1Api);
            } else if (obj instanceof V1DaemonSet) {
                resourceResult = deployDaemonSet((V1DaemonSet) obj, namespace, appsV1Api);
            } else if (obj instanceof V1PersistentVolumeClaim) {
                resourceResult = deployPersistentVolumeClaim((V1PersistentVolumeClaim) obj, namespace, coreV1Api);
            } else {
                log.warn("不支持的资源类型: {}", obj.getClass().getName());
                resourceResult.put("kind", "Unknown");
                resourceResult.put("created", false);
                resourceResult.put("error", "不支持的资源类型: " + obj.getClass().getName());
            }
        } catch (ApiException e) {
            // 处理API异常
            log.error("部署资源时发生API异常: {}", e.getResponseBody(), e);
            resourceResult.put("created", false);
            resourceResult.put("error", e.getResponseBody());
            resourceResult.put("code", e.getCode());
        } catch (Exception e) {
            // 处理其他异常
            log.error("部署资源时发生异常", e);
            resourceResult.put("created", false);
            resourceResult.put("error", e.getMessage());
        }

        return resourceResult;
    }

    /**
     * 创建部署响应
     */
    private ApiResponse<?> createDeploymentResponse(Map<String, Object> result) {
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> resources = (List<Map<String, Object>>) result.get("resources");

        if (resources == null || resources.isEmpty()) {
            return ApiResponse.error("没有找到可部署的资源");
        }

        // 检查是否有任何资源成功部署
        boolean anySuccess = resources.stream()
                .anyMatch(r -> Boolean.TRUE.equals(r.get("created")));

        if (anySuccess) {
            return ApiResponse.success(result);
        } else {
            // 有资源但都失败了
            return ApiResponse.error("所有资源部署失败");
        }
    }

    /**
     * 部署Deployment资源
     */
    private Map<String, Object> deployDeployment(V1Deployment deployment, String namespace, AppsV1Api appsV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (deployment.getMetadata().getNamespace() == null) {
            deployment.getMetadata().setNamespace(namespace);
        }
        
        // 获取容器列表，如果有镜像配置信息，将其应用到容器中
        if (deployment != null) {
            V1DeploymentSpec spec = deployment.getSpec();
            if (spec != null) {
                V1PodTemplateSpec template = spec.getTemplate();
                if (template != null) {
                    V1PodSpec podSpec = template.getSpec();
                    if (podSpec != null) {
                        List<V1Container> containers = podSpec.getContainers();
                        if (containers != null && !containers.isEmpty()) {
                            for (V1Container container : containers) {
                                if (container != null) {
                                    String image = container.getImage();
                                    if (image != null && !image.isEmpty()) {
                                        result.put("containerImage", image);
                                        // 只记录第一个容器的镜像信息
                                        log.info("从容器中提取的镜像信息: {}", image);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        var response = appsV1Api.createNamespacedDeployment(
                deployment.getMetadata().getNamespace(),
                deployment,
                null, null, null, null
        );

        result.put("kind", "Deployment");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署Deployment: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署Service资源
     */
    private Map<String, Object> deployService(V1Service service, String namespace, CoreV1Api coreV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (service.getMetadata().getNamespace() == null) {
            service.getMetadata().setNamespace(namespace);
        }

        var response = coreV1Api.createNamespacedService(
                service.getMetadata().getNamespace(),
                service,
                null, null, null, null
        );

        result.put("kind", "Service");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署Service: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署Ingress资源
     */
    private Map<String, Object> deployIngress(V1Ingress ingress, String namespace, NetworkingV1Api networkingV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (ingress.getMetadata().getNamespace() == null) {
            ingress.getMetadata().setNamespace(namespace);
        }

        var response = networkingV1Api.createNamespacedIngress(
                ingress.getMetadata().getNamespace(),
                ingress,
                null, null, null, null
        );

        result.put("kind", "Ingress");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署Ingress: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署ConfigMap资源
     */
    private Map<String, Object> deployConfigMap(V1ConfigMap configMap, String namespace, CoreV1Api coreV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (configMap.getMetadata().getNamespace() == null) {
            configMap.getMetadata().setNamespace(namespace);
        }

        var response = coreV1Api.createNamespacedConfigMap(
                configMap.getMetadata().getNamespace(),
                configMap,
                null, null, null, null
        );

        result.put("kind", "ConfigMap");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署ConfigMap: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署Secret资源
     */
    private Map<String, Object> deploySecret(V1Secret secret, String namespace, CoreV1Api coreV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (secret.getMetadata().getNamespace() == null) {
            secret.getMetadata().setNamespace(namespace);
        }

        var response = coreV1Api.createNamespacedSecret(
                secret.getMetadata().getNamespace(),
                secret,
                null, null, null, null
        );

        result.put("kind", "Secret");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署Secret: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署StatefulSet资源
     */
    private Map<String, Object> deployStatefulSet(V1StatefulSet statefulSet, String namespace, AppsV1Api appsV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (statefulSet.getMetadata().getNamespace() == null) {
            statefulSet.getMetadata().setNamespace(namespace);
        }

        var response = appsV1Api.createNamespacedStatefulSet(
                statefulSet.getMetadata().getNamespace(),
                statefulSet,
                null, null, null, null
        );

        result.put("kind", "StatefulSet");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署StatefulSet: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署DaemonSet资源
     */
    private Map<String, Object> deployDaemonSet(V1DaemonSet daemonSet, String namespace, AppsV1Api appsV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (daemonSet.getMetadata().getNamespace() == null) {
            daemonSet.getMetadata().setNamespace(namespace);
        }

        var response = appsV1Api.createNamespacedDaemonSet(
                daemonSet.getMetadata().getNamespace(),
                daemonSet,
                null, null, null, null
        );

        result.put("kind", "DaemonSet");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署DaemonSet: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 部署PersistentVolumeClaim资源
     */
    private Map<String, Object> deployPersistentVolumeClaim(V1PersistentVolumeClaim pvc, String namespace, CoreV1Api coreV1Api) throws ApiException {
        Map<String, Object> result = new HashMap<>();

        // 如果没有指定命名空间，使用请求中的命名空间
        if (pvc.getMetadata().getNamespace() == null) {
            pvc.getMetadata().setNamespace(namespace);
        }

        var response = coreV1Api.createNamespacedPersistentVolumeClaim(
                pvc.getMetadata().getNamespace(),
                pvc,
                null, null, null, null
        );

        result.put("kind", "PersistentVolumeClaim");
        result.put("name", response.getMetadata().getName());
        result.put("namespace", response.getMetadata().getNamespace());
        result.put("created", true);

        log.info("成功部署PersistentVolumeClaim: {}/{}",
                response.getMetadata().getNamespace(),
                response.getMetadata().getName());

        return result;
    }

    /**
     * 保存部署信息到dos_release表
     *
     * @param result 部署结果
     * @param releaseName 发布名称
     * @param projectId 项目ID
     * @param moduleId 模块ID
     * @param clusterId 集群ID
     * @param namespaceId 命名空间ID
     * @param envType 环境类型
     * @param yamlContent YAML内容
     */
    private void saveDeploymentInfo(Map<String, Object> result, String releaseName, 
                                   Integer projectId, Integer moduleId, Integer clusterId, 
                                   Integer namespaceId, Integer envType, String yamlContent) {
        try {
            if (result == null) {
                log.error("部署结果为空，无法保存部署信息");
                return;
            }
            
            DOSRelease dosRelease = new DOSRelease();
            dosRelease.setReleaseName(releaseName);
            dosRelease.setProjectId(projectId);
            dosRelease.setModuleId(moduleId);
            dosRelease.setClusterId(clusterId);
            dosRelease.setNamespaceId(namespaceId);
            dosRelease.setEnvType(envType);
            dosRelease.setRevision(1); // 默认为第一个版本
            dosRelease.setReleaseType(1); // 假设1表示YAML部署类型
            
            // 首先检查是否有直接从配置中提取的镜像URL
            String imageUrl = (String) result.get("imageUrl");
            if (imageUrl != null && !imageUrl.isEmpty()) {
                dosRelease.setImage(imageUrl);
                log.info("使用从配置中提取的镜像URL: {}", imageUrl);
            } else {
                // 如果没有直接提取的URL，尝试从资源中获取
                @SuppressWarnings("unchecked")
                List<Map<String, Object>> resources = (List<Map<String, Object>>) result.get("resources");
                if (resources != null && !resources.isEmpty()) {
                    // 尝试从部署资源中获取镜像信息
                    for (Map<String, Object> resource : resources) {
                        if (resource != null && "Deployment".equals(resource.get("kind"))) {
                            // 先检查是否有containerImage字段
                            Object containerImage = resource.get("containerImage");
                            if (containerImage != null) {
                                dosRelease.setImage(containerImage.toString());
                                log.info("使用容器镜像信息: {}", containerImage);
                            } else {
                                // 如果没有，使用旧的方式构造镜像信息
                                Object name = resource.get("name");
                                Object ns = resource.get("namespace");
                                if (name != null && ns != null) {
                                    dosRelease.setImage(name + ":" + ns);
                                    log.info("使用资源名称和命名空间构造镜像信息: {}", name + ":" + ns);
                                }
                            }
                            break;
                        }
                    }
                }
            }
            
            // 设置创建时间和更新时间会由MyBatis-Plus自动填充
            // 因为DOSModel中已经有了相关配置
            
            // 保存YAML内容到dos_release_yaml表
            if (yamlContent != null && !yamlContent.isEmpty()) {
                // 获取当前版本号，如果没有则设置为1
                Integer version = dosRelease.getRevision() != null ? dosRelease.getRevision() : 1;
                
                // 保存YAML内容到dos_release_yaml表
                // 由于我们还没有保存 dosRelease，所以还没有 releaseId
                // 先保存 dosRelease 以获取 ID
                boolean preSaved = dosReleaseService.save(dosRelease);
                if (!preSaved) {
                    log.error("预保存 DOSRelease 失败，无法获取 releaseId");
                    return;
                }
                
                // 获取 releaseId
                Integer releaseId = dosRelease.getId().intValue();
                
                // 保存YAML内容到dos_release_yaml表
                Integer yamlId = dosReleaseYamlService.saveYamlContent(
                    releaseId, 
                    version, 
                    yamlContent
                );
                
                if (yamlId != null) {
                    // 在dos_release表中保存yaml_id
                    dosRelease.setYamlId(yamlId);
                    log.info("保存YAML内容到dos_release_yaml表，ID: {}", yamlId);
                } else {
                    log.error("保存YAML内容到dos_release_yaml表失败");
                }
            } else {
                log.warn("YAML内容为空，无法保存到数据库");
            }
            
            // 如果已经预先保存了 dosRelease，则只需要更新
            if (yamlContent != null && !yamlContent.isEmpty() && dosRelease.getId() != null) {
                boolean updated = dosReleaseService.updateById(dosRelease);
                if (updated) {
                    log.info("成功更新部署信息到dos_release表: {}", dosRelease);
                } else {
                    log.error("更新部署信息到dos_release表失败");
                }
            } else {
                // 如果还没有保存，则调用 saveDeployment 方法保存
                boolean saved = dosReleaseService.saveDeployment(dosRelease);
                if (saved) {
                    log.info("成功保存部署信息到dos_release表: {}", dosRelease);
                } else {
                    log.error("保存部署信息到dos_release表失败");
                }
            }
        } catch (Exception e) {
            log.error("保存部署信息到dos_release表时出错", e);
        }
    }
}
